package org.fanjr.simplify.rest.factory;

import java.util.HashSet;
import java.util.Set;

import org.fanjr.simplify.rest.Rest;
import org.fanjr.simplify.rest.RestInterface;
import org.fanjr.simplify.rest.model.SimplifyServerModel;
import org.fanjr.simplify.rest.storage.SimplifyBeanBuilderStorage;
import org.fanjr.simplify.rest.utils.SimplifyClassUtil;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;

/**
 * 
 * @author fanjr@vip.qq.com
 * @since 20190222 10:29:28
 */
public class SimplifyServerFactoryProcessor implements BeanFactoryPostProcessor {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		if (beanFactory instanceof DefaultListableBeanFactory) {
			ClassLoader cl = beanFactory.getBeanClassLoader();
			String[] beanNames = beanFactory.getBeanDefinitionNames();
			for (String currName : beanNames) {
				BeanDefinition db = beanFactory.getBeanDefinition(currName);
				if (null == db.getBeanClassName()) {
					continue;
				}
				Class<?> beanType = loadClass(db.getBeanClassName(), cl);
				Rest rest = AnnotatedElementUtils.findMergedAnnotation(beanType, Rest.class);
				if (null != rest) {
					AnnotationAttributes attributes = AnnotationUtils.getAnnotationAttributes(beanType, rest);
					String prifx = (String) attributes.get("path");
					if (prifx.length() == 0) {
						prifx = currName;
					}

					Set<Class<?>> inters = new HashSet<>();
					Class<?>[] inter = (Class<?>[]) attributes.get("inter");
					for (Class<?> i : inter) {
						inters.add(i);
					}
					inters.addAll(SimplifyClassUtil.findInterfaceForAnnotation(beanType, RestInterface.class));
					doBuildModel(currName, prifx, beanType, inters);
				} else {
					Set<Class<?>> inters = SimplifyClassUtil.findInterfaceForAnnotation(beanType, RestInterface.class);
					if (inters.size() > 0) {
						doBuildModel(currName, currName, beanType, inters);
					}
				}
			}
		}
	}

	private void doBuildModel(String beanName, String prifx, Class<?> type, Set<Class<?>> inter) {
		SimplifyServerModel model = SimplifyBeanBuilderStorage.INSTANCE.buildBeanModel(beanName);
		model.setBeanType(type);
		model.setInter(inter);
		model.setPrifx(prifx);
	}

	private Class<?> loadClass(String beanName, ClassLoader cl) {
		try {
			return cl.loadClass(beanName);
		} catch (ClassNotFoundException e) {
			throw new BeanInitializationException("The bean could not be initialized!", e);
		}
	}

}
